package onlinebanking.math;

import java.math.BigInteger;

public class Rational {
	private BigInteger numerator;
	private BigInteger denominator;

	public Rational(long numerator) {
		this.numerator = new BigInteger(String.valueOf(numerator));
		this.denominator = BigInteger.ONE;
	}

	public Rational(long numerator, long denominator) {
		this.numerator = new BigInteger(String.valueOf(numerator));
		this.denominator = new BigInteger(String.valueOf(denominator));
	}

	private Rational(BigInteger numerator, BigInteger denominator) {
		this.numerator = numerator;
		this.denominator = denominator;
	}

	public Rational add(Rational x) { // a/b + c/d = (ad + bc)/bd
		BigInteger numSum = this.numerator.multiply(x.getDenominator()).add(
				this.denominator.multiply(x.getNumerator()));
		BigInteger denSum = this.denominator.multiply(x.getDenominator());
		Rational result = new Rational(numSum, denSum);
		result.simplify();
		return result;
	}

	public Rational add(long numerator, long denominator) {
		Rational result = new Rational(this.getNumerator(),
				this.getDenominator())
				.add(new Rational(numerator, denominator));
		result.simplify();
		return result;
	}
	
	public Rational add(BigInteger numerator, BigInteger denominator) {
		Rational result = new Rational(this.getNumerator(),
				this.getDenominator())
				.add(new Rational(numerator, denominator));
		result.simplify();
		return result;
	}

	public Rational subtract(Rational x) {
		return this.add(new Rational(x.getNumerator().multiply(
				new BigInteger(String.valueOf("-1"))), x.getDenominator()));
	}

	public Rational subtract(long numerator, long denominator) {
		return this.add(-1 * numerator, denominator);
	}

	public Rational multiply(Rational x) { // a/b * c/d = ac/bd
		BigInteger numProd = this.numerator.multiply(x.getNumerator());
		BigInteger denProd = this.denominator.multiply(x.getDenominator());
		Rational result = new Rational(numProd, denProd);
		result.simplify();
		return result;
	}

	public Rational multiply(long numerator, long denominator) {
		Rational result = new Rational(this.numerator, this.denominator)
				.multiply(new Rational(numerator, denominator));
		result.simplify();
		return result;
	}

	public Rational divide(Rational x) {
		return this.multiply(new Rational(x.getDenominator(), x.getNumerator()));
	}

	public Rational divide(long numerator, long denominator) {
		return this.multiply(denominator, numerator);
	}

	public static long gcd(long p, long q) {
		return (q == 0) ? p : gcd(q, p % q);
	}

	// reduces the rational number to simplest terms
	public void simplify() {
		// check for zero rational number
		if (this.numerator.compareTo(BigInteger.ZERO) == 0) {
			this.denominator = BigInteger.ONE;
			return;
		}
		BigInteger gcd = this.numerator.gcd(this.denominator);
		this.numerator = this.numerator.divide(gcd);
		this.denominator = this.denominator.divide(gcd);
	}

	public BigInteger getNumerator() {
		return this.numerator;
	}

	public BigInteger getDenominator() {
		return this.denominator;
	}

	// returns the value of the rational number
	public double evaluate() {
		return this.numerator.doubleValue() / this.denominator.doubleValue();
	}

	boolean equals(long a) {
		return this.equals(new Rational(a));
	}

	boolean equals(Rational a) {
		this.simplify();
		a.simplify();
		return (this.numerator == a.numerator && this.denominator == a.denominator);
	}

	public String toString() {
		return ((this.denominator.compareTo(BigInteger.ONE) == 0) ? this.numerator + "" : this.numerator
				+ "/" + this.denominator);
	}

}
